/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.uml_generator.bean.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.w3c.dom.Element;

import com.genia.toolbox.basics.manager.XmlManager;
import com.genia.toolbox.uml_generator.bean.GenerationConfiguration;
import com.genia.toolbox.uml_generator.bean.ModelGeneratorContext;
import com.genia.toolbox.uml_generator.model.AbstractClassModel;
import com.genia.toolbox.uml_generator.model.AbstractJavaObject;
import com.genia.toolbox.uml_generator.model.DataTypeModel;
import com.genia.toolbox.uml_generator.model.EnumerationModel;

/**
 * Class that contains the informations needed by a run of
 * {@link com.genia.toolbox.uml_generator.manager.ModelGenerator}.
 */
public class ModelGeneratorContextImpl
    implements ModelGeneratorContext
{

  /**
   * the map of the classes with the identifier of the model as the key.
   */
  private final Map<String, AbstractClassModel> classes = new TreeMap<String, AbstractClassModel>();

  /**
   * the configuration for the model generation.
   */
  private GenerationConfiguration configuration;

  /**
   * the map of the dataType with the identifier of the model as the key.
   */
  private final Map<String, DataTypeModel> dataTypes = new TreeMap<String, DataTypeModel>();

  /**
   * the {@link Set} of interfaces that have dependencies and that must be
   * declared in the Spring config file.
   */
  private final Set<AbstractClassModel> dependencies = new HashSet<AbstractClassModel>();

  /**
   * the {@link Map} of all elements indexed by their id.
   */
  private final Map<String, Element> elementsById = new HashMap<String, Element>();

  /**
   * the map of the enums with the identifier of the model as the key.
   */
  private final Map<String, EnumerationModel> enumerations = new TreeMap<String, EnumerationModel>();

  /**
   * the errors that happened during the generation.
   */
  private final List<String> errors = new ArrayList<String>();

  /**
   * the list of all generated java sources.
   */
  private final List<File> generatedSources = new ArrayList<File>();

  /**
   * the {@link XmlManager} to use.
   */
  private XmlManager xmlManager;



  /**
   * add the {@link AbstractClassModel} to the modelGenerator.
   * 
   * @param model
   *          the {@link AbstractClassModel} to add
   * @see com.genia.toolbox.uml_generator.manager.impl.ModelGeneratorContext#addClassModel(com.genia.toolbox.uml_generator.model.AbstractClassModel)
   */
  public void addClassModel(final AbstractClassModel model)
  {
    getClasses().put(model.getUmlId(), model);
  }



  /**
   * add the {@link DataTypeModel} model to the modelGenerator.
   * 
   * @param dataTypeModel
   *          the {@link DataTypeModel} to add
   * @see com.genia.toolbox.uml_generator.manager.impl.ModelGeneratorContext#addDataTypeModel(com.genia.toolbox.uml_generator.model.DataTypeModel)
   */
  public void addDataTypeModel(final DataTypeModel dataTypeModel)
  {
    getDataTypes().put(dataTypeModel.getUmlId(), dataTypeModel);
  }



  /**
   * register all elements to the list of referenceable elements. This is used
   * to be able to retrieve idref references.
   * 
   * @param elements
   *          the elements to register.
   */
  public void addElements(List<Element> elements)
  {
    for (Element element : elements) {
      String id = getXmlManager().getAttribute(element, "xmi.id");
      if (id != null) {
        elementsById.put(id, element);
      }
    }
  }



  /**
   * add the {@link EnumerationModel} to the model generator.
   * 
   * @param enumerationModel
   *          the {@link EnumerationModel} to add
   * @see com.genia.toolbox.uml_generator.manager.impl.ModelGeneratorContext#addEnumModel(com.genia.toolbox.uml_generator.model.EnumerationModel)
   */
  public void addEnumeration(final EnumerationModel enumerationModel)
  {
    getEnumerations().put(enumerationModel.getUmlId(), enumerationModel);
  }



  /**
   * getter for the classes property.
   * 
   * @return the classes
   * @see com.genia.toolbox.uml_generator.manager.impl.ModelGeneratorContext#getClasses()
   */
  public Map<String, AbstractClassModel> getClasses()
  {
    return classes;
  }



  /**
   * getter for the configuration property.
   * 
   * @return the configuration
   * @see com.genia.toolbox.uml_generator.manager.impl.ModelGeneratorContext#getConfiguration()
   */
  public GenerationConfiguration getConfiguration()
  {
    return configuration;
  }



  /**
   * getter for the dataTypeM property.
   * 
   * @return the dataTypeM
   * @see com.genia.toolbox.uml_generator.manager.impl.ModelGeneratorContext#getDataTypeM()
   */
  public Map<String, DataTypeModel> getDataTypes()
  {
    return dataTypes;
  }



  /**
   * returns the {@link Set} of interfaces that have dependencies and that must
   * be declared in the Spring config file.
   * 
   * @return the {@link Set} of interfaces that have dependencies and that must
   *         be declared in the Spring config file
   * @see com.genia.toolbox.uml_generator.bean.ModelGeneratorContext#getDependencies()
   */
  public Set<AbstractClassModel> getDependencies()
  {
    return dependencies;
  }



  /**
   * return the directory associated to the package of an object.
   * 
   * @param baseDir
   *          the base directory
   * @param object
   *          the object to inspect
   * @return the directory associated to the package
   * @see com.genia.toolbox.uml_generator.bean.ModelGeneratorContext#getDirectoryForPackage(java.io.File,
   *      com.genia.toolbox.uml_generator.model.AbstractJavaObject)
   */
  public File getDirectoryForPackage(File baseDir, AbstractJavaObject object)
  {
    return getDirectoryForPackage(baseDir, object.getPackageName());
  }



  /**
   * return the directory associated to a package.
   * 
   * @param baseDir
   *          the base directory
   * @param packageName
   *          the package name
   * @return the directory associated to the package
   * @see com.genia.toolbox.uml_generator.bean.ModelGeneratorContext#getDirectoryForPackage(java.io.File,
   *      java.lang.String)
   */
  public File getDirectoryForPackage(File baseDir, String packageName)
  {
    return new File(baseDir, packageName.replace('.', File.separatorChar));
  }



  /**
   * getter for the enumM property.
   * 
   * @return the enumM
   * @see com.genia.toolbox.uml_generator.manager.impl.ModelGeneratorContext#getEnumM()
   */
  public Map<String, EnumerationModel> getEnumerations()
  {
    return enumerations;
  }



  /**
   * getter for the errors property.
   * 
   * @return the errors
   */
  public List<String> getErrors()
  {
    return errors;
  }



  /**
   * getter for the generatedSources property.
   * 
   * @return the generatedSources
   * @see com.genia.toolbox.uml_generator.manager.impl.ModelGeneratorContext#getGeneratedSources()
   */
  public List<File> getGeneratedSources()
  {
    return generatedSources;
  }



  /**
   * returns a {@link AbstractJavaObject} knowing its identifier.
   * 
   * @param id
   *          the identifier of the object to retrieve
   * @return the {@link AbstractJavaObject} having the right identifier, or
   *         <code>null</code> if no such object exists.
   * @see com.genia.toolbox.uml_generator.manager.impl.ModelGeneratorContext#getObject(java.lang.String)
   */
  public AbstractJavaObject getObject(String id)
  {
    AbstractJavaObject res = getClasses().get(id);
    if (res != null) {
      return res;
    }
    res = getEnumerations().get(id);
    if (res != null) {
      return res;
    }
    return getDataTypes().get(id);
  }



  /**
   * returns the real element corresponding to the one given in parameter. This
   * is useful when element contains an idref.
   * 
   * @param element
   *          the element that is a reference
   * @return the referenced element
   */
  public Element getRealElement(Element element)
  {
    String id = getXmlManager().getAttribute(element, "xmi.idref");
    if (id == null) {
      return element;
    }
    return elementsById.get(id);
  }



  /**
   * getter for the xmlManager property.
   * 
   * @return the xmlManager
   */
  public XmlManager getXmlManager()
  {
    return xmlManager;
  }



  /**
   * setter for the configuration property.
   * 
   * @param configuration
   *          the configuration to set
   * @see com.genia.toolbox.uml_generator.manager.impl.ModelGeneratorContext#setConfiguration(com.genia.toolbox.uml_generator.bean.GenerationConfiguration)
   */
  public void setConfiguration(GenerationConfiguration configuration)
  {
    this.configuration = configuration;
  }



  /**
   * setter for the xmlManager property.
   * 
   * @param xmlManager
   *          the xmlManager to set
   */
  public void setXmlManager(XmlManager xmlManager)
  {
    this.xmlManager = xmlManager;
  }

}
